/**
 * Copyright (C) 2011 - @le.nguyen
 * @Created Jul 28, 2011
 *
 * TODO
 */
package com.conan.app.dailyflickr.activity;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;

import com.conan.app.dailyflickr.App;
import com.conan.app.dailyflickr.AppData;
import com.conan.app.dailyflickr.utils.BitmapUtils;
import com.conan.app.dailyflickr.utils.zoom.DynamicZoomControl;
import com.conan.app.dailyflickr.utils.zoom.ImageZoomView;
import com.conan.app.dailyflickr.utils.zoom.PinchZoomListener;
import com.conan.app.flickrdaily.R;

/**  */
public class DowloadedPhotosActivity extends Activity implements ImageLoadingListener, OnGestureListener{
    private final String TAG = "DowloadedPhotos";
    private Gallery gallery;
    // private ImageView imgView;
    private ImageZoomView mZoomView;
    /** Zoom control */
    private DynamicZoomControl mZoomControl;
    private PinchZoomListener mPinchZoomListener;
    
    ImageAdapter mAdapter;
    private GestureDetector gestureScanner;
    
    String[] projection = { MediaStore.Images.ImageColumns._ID,
            MediaStore.Images.ImageColumns.DATA};
    String[] projection_thumbs = { MediaStore.Images.Thumbnails._ID};
    int mProjection_Id                  = 0;
    int mProjection_Data                = 1;
    int mProjection_thumb_Id            = 0;
    int mProjection_thumb_imgId         = 1;
    int mCurrPosition = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {	
        super.onCreate(savedInstanceState);
        setContentView(R.layout.download_photos_activity);
        
        gestureScanner = new GestureDetector(this);
        initZoomView();
        
        gallery = (Gallery) findViewById(R.id.gallery);
        gallery.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                setCurrentMainPhotoView(position);

            }
        });
        gallery.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                scanToClearCache(arg2 - 5,  arg2 + 5);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub
            }
        });

        // Query for all images on external storage
        init_data();
    }	

    Bitmap mainBitmap = null;
    private void init_data(){
        String filter =  MediaStore.MediaColumns.DATA + " like '%" + AppData.DOWNLOAD_FOLDER + "/%'"; 
        // filter = "(" + filter + ") AND " + getMediaTypeFilter();
        
        Cursor mImageCursor = null;
        try {
            mImageCursor = getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, 
                    filter , null, null);
        } catch (android.database.sqlite.SQLiteMisuseException e) {
            Log.e(TAG, ">>> SQLite error: " + e.toString());
        } catch (android.database.sqlite.SQLiteException e) {
            Log.e(TAG, ">>> SQLite error: " + e.toString());
        }
        
        // Initialize an adapter to display images in grid
        Cursor cursor = null;
        int columnIndex = 0;
        if ( mImageCursor != null ) {
            if (mImageCursor.moveToFirst() == true) {
                for (;;) {
                    ImageData data = new ImageData();
                    data._imageID = mImageCursor.getInt(mProjection_Id);
                    data._url = mImageCursor.getString(mProjection_Data);
                    
                    filter = MediaStore.Images.Thumbnails.IMAGE_ID + " = " + data._imageID;
                    cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
                            projection_thumbs, filter, null, null );
                    
                    if(cursor != null && cursor.moveToFirst() == true){
                        columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
                        data._thumbID = cursor.getInt(columnIndex);
                        cursor.close();
                    }
                    
                    mImages.add(data);
                    if(!mImageCursor.moveToNext()) break;
                }
            }
            
            mImageCursor.close();
            
            mAdapter = new ImageAdapter(this);
            gallery.setAdapter(mAdapter);
            
            if(mImages == null || mImages.size() == 0){
                // Toast.makeText(this, getString(R.string.no_photos), 0).show();
                AlertDialog dialog = new AlertDialog.Builder(this)
                .setMessage(getString(R.string.no_photos))
                .setPositiveButton("OK", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                }).create();
                dialog.show();
                return;
            }
            
            Random ran = new Random();
            int position = ran.nextInt(mImages.size());
            gallery.setSelection(position, true);
            ImageData data = mImages.get(position);
            try{
                Bitmap newBitmap = BitmapFactory.decodeFile( data._url, null );
                if(newBitmap != null){
                    // imgView.setImageBitmap(newBitmap);
                    setBitmapToZoomView(newBitmap);
                }else{
                    // imgView.setImageResource(R.drawable.no_image);
                    setBitmapToZoomView(null);
                }
            }catch (OutOfMemoryError e) {
                e.printStackTrace();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    protected void onDestroy() {
        clearAllCache();
        stopLoadingTask();
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.image_menu,menu);
        MenuItem itemDelete = (MenuItem)menu.findItem(R.id.delete);
        itemDelete.setIcon(android.R.drawable.ic_menu_delete);
        MenuItem itemWallpaper = (MenuItem)menu.findItem(R.id.wallpaper);
        itemWallpaper.setIcon(android.R.drawable.ic_menu_set_as);
        MenuItem itemShare = (MenuItem)menu.findItem(R.id.share);
        itemShare.setIcon(android.R.drawable.ic_menu_share);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemSelected = gallery.getSelectedItemPosition();
        if(itemSelected == AdapterView.INVALID_POSITION) return true;

        ImageData image = mImages.get(itemSelected);

        switch (item.getItemId()) {
        case R.id.wallpaper:
            setAsWallpaper(image._url);

            return true;
        case R.id.delete:
            deleteImage(image._url);

            return true;
        case R.id.share:
            shareImage(image._url);

            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /***************************************************************************************************
     *************************************************************************************************** 
     ***************************************************************************************************/
    private void shareImage(String filePath){
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        Uri screenshotUri = Uri.parse(filePath);

        shareIntent.setType("image/jpeg");
        shareIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
        startActivity(Intent.createChooser(shareIntent, getString(R.string.share_title)));
    }

    private void deleteImage(String filepath){
        if(TextUtils.isEmpty(filepath)) return;

        File image = new File(filepath);
        if(image.exists()){
            image.delete();
        }
    }

    private void setAsWallpaper(String filepath){
        if(TextUtils.isEmpty(filepath)) return;

        BitmapFactory.Options bounds = new BitmapFactory.Options();
        bounds.inJustDecodeBounds = true;

        Bitmap bitmap = BitmapFactory.decodeFile(filepath);

        if(bitmap == null) {
            Toast.makeText(this, "Set as Wallpaper failed."/* + filepath*/, 0).show();
            return;
        }

        try {
            WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
            wallpaperManager.setBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();

        }
    }

    protected Bitmap loadThumbnailImage( int imageID , String url) {
        try{
            Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(this.getContentResolver(),
                    imageID, MediaStore.Images.Thumbnails.MINI_KIND, null);
            // load thumb from url
            Bitmap source = BitmapFactory.decodeFile(url);
            thumb = BitmapUtils.compressToMiniThumbnail(source, true, 80);
            return thumb;
        }catch (OutOfMemoryError e) {
            Log.e(TAG, "loadThumbnailImage() failed caused OOM");
        }
        return null;
    }

    @Override
    public void completed(int position, Bitmap bitmap) {
        if(position < 0){
            // imgView.setImageBitmap(bitmap);
            setBitmapToZoomView(bitmap);

        }else{
            if(mHandler != null){
                mHandler.sendEmptyMessage(UPDATE_DATASET_VIEW);
            }
        }

    }

    private final int UPDATE_DATASET_VIEW = 101;
    Handler mHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case UPDATE_DATASET_VIEW:
                if(mAdapter != null){
                    mAdapter.notifyDataSetChanged();
                }
                break;

            default:
                break;
            }
        };
    };

    ArrayList<ImageData> mImages = new ArrayList<ImageData>();
    /***************************************************************************************************
     ****************************	CACHE	************************************************************ 
     ***************************************************************************************************/
    ConcurrentHashMap<Integer, Bitmap> mCache = new ConcurrentHashMap<Integer, Bitmap>();
    ImageLoadingTask getImageTask;

    private void scanToClearCache(int start, int end){
        if(mImages == null) return;
        if(start < 0) start = 0;
        if(end >= mImages.size()) end = mImages.size() - 1;
        synchronized (mCache) {
            for(int key: mCache.keySet()){
                if(key < start || key > end) {
                    Bitmap bitmap = mCache.remove(key);
                    if(bitmap != null){
                        bitmap.recycle();
                        bitmap = null;
                    }
                }
            }
        }
    }

    //	private boolean isBelongsTo(String key, ArrayList<String> keys){
    //		if(keys == null || keys.size() == 0) return false;
    //		for(String item: keys){
    //			if(TextUtils.equals(key, item)) return true;
    //		}
    //		return false;
    //	}

    private void clearAllCache(){
        if(mCache == null) return;
        synchronized (mCache) {
            for(int key: mCache.keySet()){
                Bitmap bm = mCache.get(key);
                if(bm != null){
                    bm.recycle();
                    bm = null;
                }
            }

            mCache.clear();
        }		
    }

    public void startDownload(QueueItem queueItem, boolean isMainView){
        if(getImageTask != null && 
                (getImageTask.getStatus() == AsyncTask.Status.RUNNING ||
                getImageTask.isRunning)){
            getImageTask.setListener(this);
            // if(isMainView){
            getImageTask.addFirstUrlDownload(queueItem);
            // }else{
            getImageTask.addUrlDownload(queueItem);
            // }
        }else{
            getImageTask = new ImageLoadingTask(
                    App.getContext(), 
                    queueItem, isMainView);
            getImageTask.setListener(this);
            try{
                getImageTask.execute();				
            }catch (RejectedExecutionException e) {	
                e.printStackTrace();
            }
        }
    }

    /**
     * stop download task
     */
    public void stopLoadingTask(){		
        if(getImageTask != null && getImageTask.getStatus() == AsyncTask.Status.RUNNING ){
            getImageTask.cancel(true);
        }
        getImageTask = null;
    }
    class ImageLoadingTask extends AsyncTask<Void, Void, Void>{
        private static final String TAG = "ImageLoadingTask";
        public boolean isRunning = false;
        private Context mContext;

        private ImageLoadingListener mListener;
        private ArrayList<QueueItem> mPrepareGetUrl = new ArrayList<QueueItem>();			

        public ImageLoadingTask(Context context, QueueItem item, boolean isMain){
            mContext = context;
            if(isMain){
                addFirstUrlDownload(item);
            }else{
                addUrlDownload(item);
            }
        }			

        public void setListener(ImageLoadingListener listener){
            mListener = listener;
        }			

        private void addUrlDownload(QueueItem item){
            if(mPrepareGetUrl.contains(item)) return;
            synchronized (mPrepareGetUrl) {
                mPrepareGetUrl.add(item);					
                mPrepareGetUrl.notifyAll();
            }
        }

        private void addFirstUrlDownload(QueueItem item){
            synchronized (mPrepareGetUrl) {
                if(mPrepareGetUrl.contains(item)) {
                    mPrepareGetUrl.remove(item);
                }

                mPrepareGetUrl.add(0, item);					
                mPrepareGetUrl.notifyAll();
            }
        }

        /**
         * clear old request
         */
        public void clearRequestLoading(){
            synchronized (mPrepareGetUrl) {
                mPrepareGetUrl.clear();
            }
        }


        @Override
        protected Void doInBackground(Void... params) {
            isRunning = true;

            while(!mPrepareGetUrl.isEmpty()){
                //TODO : set imageView to a "pending" image

                QueueItem item = mPrepareGetUrl.remove(0);
                Bitmap bitmap = loadThumbnailImage(item._id, item._url);
                // in case thumbnail still not create			

                if( bitmap!= null ){	
                    mCache.put(item._position, bitmap);
                    // pop item from dataCache 
                    if(mListener != null){
                        mListener.completed(item._position, bitmap);
                    }
                }else{
                    mPrepareGetUrl.add(item);
                }
            }

            isRunning = false;
            return null;
        }

        @Override
        protected void onCancelled() {
            isRunning = false;

            if(mPrepareGetUrl != null){
                mPrepareGetUrl.clear();
                mPrepareGetUrl = null;
            }
            super.onCancelled();
        }
    }

    class QueueItem{
        int _position;
        String _url;
        int _id;
        public QueueItem(int position, int id, String url) {
            _id = id;
            _position = position;
            _url = url;
        }
    }


    /***************************************************************************************************
     ****************************	Adapter	************************************************************* 
     ***************************************************************************************************/
    int GalItemBg;
    public class ImageAdapter extends BaseAdapter {
        int GalItemBg;
        private Context cont;

        public ImageAdapter(Context c) {
            cont = c;
            TypedArray typArray = obtainStyledAttributes(R.styleable.GalleryTheme);
            GalItemBg = typArray.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 0);
            typArray.recycle();
        }

        public int getCount() {
            return mImages.size();
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imgView = new ImageView(cont);

            ImageData data = mImages.get(position);
            Bitmap bm = null;
            if(data._thumbID >= 0){
                bm = mCache.get(position);
            }

            if(bm != null){
                imgView.setImageBitmap(bm);
            }else{
                if(DowloadedPhotosActivity.this != null){
                    startDownload(new QueueItem(position, data._imageID, data._url), false);
                }
                imgView.setImageResource(R.drawable.no_image);
            }

            imgView.setLayoutParams(new Gallery.LayoutParams(125, 110));
            imgView.setScaleType(ImageView.ScaleType.FIT_XY);
            imgView.setBackgroundResource(GalItemBg);

            return imgView;
        }
    }


    private String getMediaTypeFilter(){
        return "((LOWER(mime_type) = 'image/jpeg') OR ( LOWER("
                + Images.Media.MIME_TYPE + ") = 'image/jpg') OR ( LOWER("
                + Images.Media.MIME_TYPE + ") = 'image/png') OR ( LOWER(" 
                + Images.Media.MIME_TYPE + ") = 'image/bmp') OR ( LOWER("
                + Images.Media.MIME_TYPE + ") = 'image/gif') OR ( LOWER("
                + Images.Media.MIME_TYPE + ") = 'image/vnd.wap.wbmp') OR ( LOWER("
                + Images.Media.MIME_TYPE + ") = 'image/x-ms-bmp'))"
                + " AND " 
                + " (" + Images.Media.SIZE + "> 0)  "
                +" AND (NOT ( LOWER("
                + Images.Media.DISPLAY_NAME +") = 'front.jpg'))"
                +" AND (NOT ( LOWER("
                + Images.Media.DISPLAY_NAME +") = 'back.jpg'))"
                +" AND (NOT "                    
                + Images.Media.DISPLAY_NAME +" LIKE 'Cover.jpg')"
                +" AND (NOT "                    
                + Images.Media.DISPLAY_NAME +" LIKE 'CD.jpg')";
    }

    private class ImageData{
        public ImageData() {
            _thumbID = -1;
        }
        int _thumbID;
        int _imageID;
        String _url;
    }


    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }


    @Override
    public void onShowPress(MotionEvent e) { }


    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }


    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        return false;
    }


    @Override
    public void onLongPress(MotionEvent e) { }


    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        try {
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            // right to left swipe
            if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                // Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show();
                setCurrentMainPhotoView(mCurrPosition - 1);
                gallery.setSelection(mCurrPosition);
            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                // Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
                setCurrentMainPhotoView(mCurrPosition + 1);
                gallery.setSelection(mCurrPosition);
            }

        } catch (Exception e) {
            // nothing
        }
        return true;
    }
    
    private void setCurrentMainPhotoView(int position){
        if(position < 0) position = mImages.size() - 1;
        if(position > mImages.size() - 1) position = 0;
        Bitmap newBitmap = null;
        try{
            mCurrPosition = position;
            ImageData data = mImages.get(position);
            newBitmap = BitmapFactory.decodeFile( data._url, null );
        }catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        
        mZoomView.setImage(newBitmap);
        if(newBitmap != null){
            // imgView.setImageBitmap(newBitmap);
            mZoomView.setBackgroundResource(0);
        }else{
            // mgView.setImageResource(R.drawable.no_image);
            mZoomView.setBackgroundResource(R.drawable.no_image);
        }

        if(mainBitmap != null){
            mainBitmap.recycle();
        }
        mainBitmap = newBitmap;
    }

    private void initZoomView(){
        mZoomControl = new DynamicZoomControl();
        mPinchZoomListener = new PinchZoomListener(getApplicationContext());
        mPinchZoomListener.setZoomControl(mZoomControl);
        mZoomView = (ImageZoomView)findViewById(R.id.ImageView);
        mZoomView.setZoomState(mZoomControl.getZoomState());
        mZoomControl.setAspectQuotient(mZoomView.getAspectQuotient());
        // Reset zoom state and notify observers
        if (mZoomControl != null) {
            mZoomControl.getZoomState().setPanX(0.5f);
            mZoomControl.getZoomState().setPanY(0.5f);
            mZoomControl.getZoomState().setZoom(1f);
            mZoomControl.getZoomState().notifyObservers();
        }
        /*imgView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(final View view, final MotionEvent event) {
               return gestureScanner.onTouchEvent(event);
            }
         });*/
    }
    private void setBitmapToZoomView(Bitmap bmp) {
        mZoomView.setImage(bmp);
        if (bmp != null) {
            mZoomView.setOnTouchListener(mPinchZoomListener);
            mPinchZoomListener.setImageZoomView(mZoomView);
        } else {
            mZoomView.setOnTouchListener(null);
            mPinchZoomListener.setImageZoomView(null);
        }
    }
}
